/**
 * Property-based tests for scene utilities
 * Feature: emotion-3d-website, Property 1: Scene Initialization Completeness
 * Validates: Requirements 1.1, 1.5
 */

import { describe, it, expect } from 'vitest';
import fc from 'fast-check';
import {
  generateInitialSceneObjects,
  validateSceneInitialization,
  generateFloatingObject,
  FLOATING_OBJECT_CONFIGS,
} from './sceneUtils';
import { FloatingObject, FloatingObjectType } from '@/types';

describe('Scene Initialization', () => {
  /**
   * Feature: emotion-3d-website, Property 1: Scene Initialization Completeness
   * For any 3D scene initialization, the scene SHALL contain at least 10 floating objects
   * AND include at least one object from each category (emoji, food, nature).
   */
  it('should always generate scenes with at least 10 objects and all categories', () => {
    fc.assert(
      fc.property(
        fc.constant(null), // We don't need random input, just testing the generator
        () => {
          const objects = generateInitialSceneObjects();
          
          // Check minimum count
          expect(objects.length).toBeGreaterThanOrEqual(10);
          
          // Check for at least one object from each category
          const hasEmoji = objects.some(obj => obj.type === 'emoji');
          const hasFood = objects.some(obj => obj.type === 'food');
          const hasNature = objects.some(obj => obj.type === 'nature');
          
          expect(hasEmoji).toBe(true);
          expect(hasFood).toBe(true);
          expect(hasNature).toBe(true);
          
          // Validate using the validation function
          expect(validateSceneInitialization(objects)).toBe(true);
          
          return true;
        }
      ),
      { numRuns: 100 }
    );
  });

  it('should validate scene initialization correctly', () => {
    fc.assert(
      fc.property(
        fc.array(
          fc.record({
            id: fc.string(),
            type: fc.constantFrom('emoji' as FloatingObjectType, 'food' as FloatingObjectType, 'nature' as FloatingObjectType),
            modelPath: fc.string(),
            position: fc.record({
              x: fc.float(),
              y: fc.float(),
              z: fc.float(),
            }),
            rotation: fc.record({
              x: fc.float(),
              y: fc.float(),
              z: fc.float(),
            }),
            scale: fc.float({ min: Math.fround(0.1), max: Math.fround(3) }),
            animationSpeed: fc.float({ min: Math.fround(0.1), max: Math.fround(5) }),
          }),
          { minLength: 0, maxLength: 20 }
        ),
        (objects: FloatingObject[]) => {
          const isValid = validateSceneInitialization(objects);
          
          // If valid, must have at least 10 objects and all categories
          if (isValid) {
            expect(objects.length).toBeGreaterThanOrEqual(10);
            expect(objects.some(obj => obj.type === 'emoji')).toBe(true);
            expect(objects.some(obj => obj.type === 'food')).toBe(true);
            expect(objects.some(obj => obj.type === 'nature')).toBe(true);
          }
          
          // If invalid, must be missing count or categories
          if (!isValid) {
            const hasMinCount = objects.length >= 10;
            const hasAllCategories = 
              objects.some(obj => obj.type === 'emoji') &&
              objects.some(obj => obj.type === 'food') &&
              objects.some(obj => obj.type === 'nature');
            
            expect(hasMinCount && hasAllCategories).toBe(false);
          }
          
          return true;
        }
      ),
      { numRuns: 100 }
    );
  });

  it('should generate valid floating objects', () => {
    fc.assert(
      fc.property(
        fc.constantFrom(...FLOATING_OBJECT_CONFIGS),
        fc.integer({ min: 0, max: 100 }),
        (config, index) => {
          const object = generateFloatingObject(config.id, config.type, index);
          
          // Verify object structure
          expect(object.id).toBe(config.id);
          expect(object.type).toBe(config.type);
          expect(typeof object.position.x).toBe('number');
          expect(typeof object.position.y).toBe('number');
          expect(typeof object.position.z).toBe('number');
          expect(typeof object.rotation.x).toBe('number');
          expect(typeof object.rotation.y).toBe('number');
          expect(typeof object.rotation.z).toBe('number');
          expect(typeof object.scale).toBe('number');
          expect(typeof object.animationSpeed).toBe('number');
          
          // Verify reasonable ranges
          expect(object.scale).toBeGreaterThan(0);
          expect(object.animationSpeed).toBeGreaterThan(0);
          
          return true;
        }
      ),
      { numRuns: 100 }
    );
  });
});
